package _0util;



import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: RSA算法加密解密工具类
 * @Author wangzhen
 * @Date 2020/05/20
 **/
public class RSAutil {


    public static final String ALGORITHM="RSA";

    //RSA加密长度，最小512
    private static final int KEY_SIZE=512;

    //公钥
    public static final String PUBLIC_KEY = "RSAPublicKey";

    //私钥
    public static final String PRIVATE_KEY = "RSAPrivateKey";

    //存储钥匙对
    private static Map<String,Key> KEY_MAP=new HashMap<>();

    //写出key文件的路径
    private static final String FILE_PATH = "./keys";



    /**
     * 生成密匙对
     *
     * @throws Exception
     */
    public static void initKey() {
        try {

            //实例化密钥生成器
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);

            //初始化密钥长度
            keyPairGenerator.initialize(KEY_SIZE);

            //生成密钥对
            KeyPair keyPair = keyPairGenerator.generateKeyPair();

            //公钥
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

            //私钥
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

            //将密钥存储在map中
            KEY_MAP.put(PUBLIC_KEY, publicKey);
            KEY_MAP.put(PRIVATE_KEY, privateKey);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    public static void outputKeyFile() {
        Key publicKey = KEY_MAP.get(PUBLIC_KEY);
        Key privateKey = KEY_MAP.get(PRIVATE_KEY);

        File file = new File(FILE_PATH);
        if (!file.exists()) {
            file.mkdirs();
        }

        try (BufferedOutputStream publicKeyOutput = new BufferedOutputStream(new FileOutputStream(FILE_PATH + File.separator + "publickey.txt"));
             BufferedOutputStream privateKeyOutput = new BufferedOutputStream(new FileOutputStream(FILE_PATH + File.separator + "privatekey.txt"))) {

            String puk = Base64.getEncoder().encodeToString(publicKey.getEncoded());
            String prk = Base64.getEncoder().encodeToString(privateKey.getEncoded());

            publicKeyOutput.write(puk.getBytes());
            privateKeyOutput.write(prk.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 销毁钥匙
     */
    public static void destroyKeys(){
        KEY_MAP=null;
    }


    /**
     * 获得公钥
     * @return
     */
    public static byte[] getPublicKey(){
        if(KEY_MAP==null){
            initKey();
            outputKeyFile();
        }

        Key key = KEY_MAP.get(PUBLIC_KEY);
        return key.getEncoded();
    }


    /**
     * 获得私钥
     * @return
     */
    public static byte[] getPrivateKey(){
        if(KEY_MAP==null){
            initKey();
            outputKeyFile();
        }

        Key key = KEY_MAP.get(PRIVATE_KEY);
        return key.getEncoded();
    }


    /**
     * 私钥加密
     * @param data
     * @param privatekey
     * @return
     * @throws Exception
     */
    public static byte[] privateKeyEncryption(byte[] data,byte[] privatekey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {
        //String privatekey="fnjoakJp1M88Mi83zpA77IorxkG71BplC4GUf9LqfZ2EGxOr9hmMwIhAJQhtMFFShnLCEHtgJZjD3q8U9eebOS8aV/BrBKyYrjRAiEAx1b3zKncXgrJjHiaL7Xw2JQYRZDfswDKpLdCtCyvTbMCIHCgi9aJM+XWFwugwLAxNh+7Un/IoobL3rc3pI+uxYfZ";
        //String data="abc123";

        //取得私钥
        //byte[] decode = Base64.getDecoder().decode(privatekey.getBytes());
        //PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(decode);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privatekey);
        KeyFactory keyFactory = KeyFactory.getInstance(RSAutil.ALGORITHM);

        //生成私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        //数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(data);
        //编码转换为Base字符
        //String encode = Base64.getEncoder().encodeToString(bytes);
        //System.out.println(encode);//dXfRJ9eYoAo4Oz1F+dTFlqTSU2+DhY5ZS/O7HarhbcMa15a4fxrkI9Y+EAkRxADi359PgDT3LVJdYLfRRqg+JA==

    }


    /**
     * 私钥解密
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     */
    public static byte[] privateKeyDecrypt(byte[] data, byte[] privateKey) throws Exception{

        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(RSAutil.ALGORITHM);

        //密钥材料转换
        PKCS8EncodedKeySpec spec=new PKCS8EncodedKeySpec(privateKey);

        //产生私钥
        PrivateKey Key = keyFactory.generatePrivate(spec);

        //数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, Key);
        return cipher.doFinal(data);
    }


    /**
     * 公钥加密
     * @param data
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static byte[] publicKeyEncrypt( byte[] data, byte[] publicKey) throws Exception{

        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(RSAutil.ALGORITHM);

        //初始化公钥
        //密钥材料转换
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);

        //产生公钥
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);

        //数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return cipher.doFinal(data);
    }


    /**
     * 公钥解密
     * @param data 保证数据是原始密文，已经解码
     * @param publicKey  保证key是原始密文，已经解码
     * @return
     * @throws Exception
     */
    public static byte[] publicKeyDecrypt(byte[] data,byte[] publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {

        //实例化密钥工厂
        KeyFactory keyFactory = KeyFactory.getInstance(RSAutil.ALGORITHM);

        //初始化公钥
        //密钥材料转换
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);

        //产生公钥
        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);

        //数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, pubKey);
        return cipher.doFinal(data);
    }


}
